Skip to main content

Admin API Reference

This page is a reference: it describes, endpoint by endpoint, the APIs that the TideCloak admin implementation (the tide-console SPA and the admin operations it performs) calls. It is information-oriented and code-determined. It does not teach concepts or walk through procedures.

Conventions

  • {realm} is the realm path segment. {id} and similarly named placeholders are entity identifiers.
  • Base prefixes used below:
    • /admin/realms/{realm}/... is the Keycloak admin REST base (admin token required).
    • /admin/realms/{realm}/vendorResources/..., /admin/realms/{realm}/iga/..., /admin/realms/{realm}/ragnarok/..., /admin/realms/{realm}/tide-admin/..., and /admin/realms/{realm}/tideAdminResources/... are Tide-specific admin resources mounted on the admin REST base.
    • /realms/{realm}/public/... and /realms/{realm}/tide-console/... are public, pre-authentication resources.
  • Auth column meanings:
    • manage-realm = an admin access token whose realm-management permissions satisfy requireManageRealm().
    • view client = requireView(client) on the named client.
    • public = no token (pre-authentication).
  • Governed: whether the call is subject to IGA capture. A governed write may return 202 Accepted with a change-request id instead of applying immediately. See IGA governance / change requests and the Management API governance section.
  • File references point at the @Path/@GET/@POST annotations in source that this page was written from, so each entry can be verified against the code.

1. Realm and admin core (Keycloak admin REST)

The SPA performs most realm, user, client, role, group, client-scope, organization, identity-provider, session, and admin-event operations through the standard Keycloak Admin REST API. These endpoints are not Tide-specific and are documented in full upstream:

The api-client (tidecloak-key-provider/frontend/packages/api-client/src/keycloak/*) calls the following standard endpoints. Method + path + one-line purpose only; consult the upstream reference for parameters and response schemas. All require an admin token (manage-realm/view-realm or the corresponding resource permission).

Realms, server info, permissions

MethodPathPurpose
GET/admin/realmsList realms.
POST/admin/realmsCreate a realm.
GET/admin/realms/{realm}Get realm representation.
PUT/admin/realms/{realm}Update realm.
GET/admin/realms/{realm}/admin-eventsList admin audit events.
GET/admin/serverinfoServer version / capabilities.
GET/admin/realms/{realm}/users-management-permissionsProbe fine-grained admin feature.
GET/admin/realms/{realm}/{resource}/{id}/management/permissionsGet resource (role/group/client) permissions.
PUT/admin/realms/{realm}/{resource}/{id}/management/permissionsEnable/disable resource permissions.
GET/admin/realms/{realm}/componentsLook up a component (e.g. key provider) by providerId.

Identity providers and required actions

MethodPathPurpose
GET/admin/realms/{realm}/identity-provider/instancesList identity providers.
GET/admin/realms/{realm}/identity-provider/instances/{alias}Get an identity provider.
PUT/admin/realms/{realm}/identity-provider/instances/{alias}Update an identity provider.
DELETE/admin/realms/{realm}/identity-provider/instances/{alias}Delete an identity provider.
GET/admin/realms/{realm}/authentication/required-actionsList required actions.
POST/admin/realms/{realm}/authentication/register-required-actionRegister a required-action provider.

Users

MethodPathPurpose
GET/admin/realms/{realm}/usersList / search users.
GET/admin/realms/{realm}/users/countCount users.
GET/admin/realms/{realm}/users/{id}Get a user.
POST/admin/realms/{realm}/usersCreate a user.
PUT/admin/realms/{realm}/users/{id}Update a user.
DELETE/admin/realms/{realm}/users/{id}Delete a user.
GET/admin/realms/{realm}/users/{id}/credentialsList user credentials.
POST/admin/realms/{realm}/users/{id}/credentials/{credentialId}/userLabelSet a credential label.
DELETE/admin/realms/{realm}/users/{id}/credentials/{credentialId}Remove a credential.
GET/admin/realms/{realm}/users/{id}/groupsList a user's groups.
POST/admin/realms/{realm}/users/{id}/groups/{groupId}Add user to group.
DELETE/admin/realms/{realm}/users/{id}/groups/{groupId}Remove user from group.
GET/admin/realms/{realm}/users/{id}/role-mappingsList all role mappings.
GET/admin/realms/{realm}/users/{id}/role-mappings/realmList realm role mappings.
GET/admin/realms/{realm}/users/{id}/role-mappings/realm/availableList available realm roles.
POST/admin/realms/{realm}/users/{id}/role-mappings/realmAssign realm roles.
DELETE/admin/realms/{realm}/users/{id}/role-mappings/realmRemove realm roles.
GET/admin/realms/{realm}/users/{id}/role-mappings/clients/{clientUuid}List client role mappings.
GET/admin/realms/{realm}/users/{id}/role-mappings/clients/{clientUuid}/availableList available client roles.
POST/admin/realms/{realm}/users/{id}/role-mappings/clients/{clientUuid}Assign client roles.
DELETE/admin/realms/{realm}/users/{id}/role-mappings/clients/{clientUuid}Remove client roles.
GET/admin/realms/{realm}/users/{id}/federated-identityList federated identities.
DELETE/admin/realms/{realm}/users/{id}/federated-identity/{provider}Remove a federated link.
GET/admin/realms/{realm}/users/{id}/user-sessionsList user sessions.
GET/admin/realms/{realm}/users/{id}/consentsList user consents.

Groups

MethodPathPurpose
GET/admin/realms/{realm}/groupsList groups.
GET/admin/realms/{realm}/groups/countCount groups.
GET/admin/realms/{realm}/groups/{id}Get a group.
GET/admin/realms/{realm}/groups/{id}/childrenList child groups.
POST/admin/realms/{realm}/groupsCreate a root group.
POST/admin/realms/{realm}/groups/{parentId}/childrenCreate child group / move group.
PUT/admin/realms/{realm}/groups/{id}Update a group.
DELETE/admin/realms/{realm}/groups/{id}Delete a group.
GET/admin/realms/{realm}/groups/{id}/membersList group members.
GET/admin/realms/{realm}/groups/{id}/role-mappings/realmList group realm roles.
GET/admin/realms/{realm}/groups/{id}/role-mappings/realm/availableList available realm roles.
POST/admin/realms/{realm}/groups/{id}/role-mappings/realmAdd realm roles.
DELETE/admin/realms/{realm}/groups/{id}/role-mappings/realmRemove realm roles.
GET/admin/realms/{realm}/groups/{id}/role-mappings/clients/{clientUuid}List group client roles.
GET/admin/realms/{realm}/groups/{id}/role-mappings/clients/{clientUuid}/availableList available client roles.
POST/admin/realms/{realm}/groups/{id}/role-mappings/clients/{clientUuid}Add client roles.
DELETE/admin/realms/{realm}/groups/{id}/role-mappings/clients/{clientUuid}Remove client roles.

Roles

MethodPathPurpose
GET/admin/realms/{realm}/rolesList realm roles.
GET/admin/realms/{realm}/roles/{roleName}Get realm role by name.
GET/admin/realms/{realm}/roles-by-id/{roleId}Get role by id.
POST/admin/realms/{realm}/rolesCreate a realm role.
PUT/admin/realms/{realm}/roles-by-id/{roleId}Update a role.
DELETE/admin/realms/{realm}/roles-by-id/{roleId}Delete a role.
GET/admin/realms/{realm}/roles-by-id/{roleId}/compositesList composite children.
POST/admin/realms/{realm}/roles-by-id/{roleId}/compositesAdd composite children.
DELETE/admin/realms/{realm}/roles-by-id/{roleId}/compositesRemove composite children.
GET/admin/realms/{realm}/roles/{roleName}/usersList users holding a role.

Clients and client scopes

MethodPathPurpose
GET/admin/realms/{realm}/clientsList clients.
GET/admin/realms/{realm}/clients/{id}Get a client.
POST/admin/realms/{realm}/clientsCreate a client.
PUT/admin/realms/{realm}/clients/{id}Update a client.
DELETE/admin/realms/{realm}/clients/{id}Delete a client.
GET/admin/realms/{realm}/clients/{id}/client-secretGet client secret.
POST/admin/realms/{realm}/clients/{id}/client-secretRegenerate client secret.
GET/admin/realms/{realm}/clients/{id}/protocol-mappers/modelsList protocol mappers.
POST/admin/realms/{realm}/clients/{id}/protocol-mappers/modelsCreate a protocol mapper.
PUT/admin/realms/{realm}/clients/{id}/protocol-mappers/models/{mapperId}Update a protocol mapper.
DELETE/admin/realms/{realm}/clients/{id}/protocol-mappers/models/{mapperId}Delete a protocol mapper.
GET/admin/realms/{realm}/clients/{id}/rolesList client roles.
GET/admin/realms/{realm}/clients/{id}/user-sessionsList client user sessions.
GET/admin/realms/{realm}/clients/{id}/default-client-scopesList default client scopes.
PUT/admin/realms/{realm}/clients/{id}/default-client-scopes/{scopeId}Add a default client scope.
DELETE/admin/realms/{realm}/clients/{id}/default-client-scopes/{scopeId}Remove a default client scope.
GET/admin/realms/{realm}/clients/{id}/optional-client-scopesList optional client scopes.
PUT/admin/realms/{realm}/clients/{id}/optional-client-scopes/{scopeId}Add an optional client scope.
DELETE/admin/realms/{realm}/clients/{id}/optional-client-scopes/{scopeId}Remove an optional client scope.
GET/admin/realms/{realm}/clients/{id}/authz/resource-serverGet authorization config.
PUT/admin/realms/{realm}/clients/{id}/authz/resource-serverUpdate authorization config.
GET/admin/realms/{realm}/clients/{id}/service-account-userGet the service-account user.
GET/admin/realms/{realm}/client-scopesList client scopes.

Sessions and organizations

MethodPathPurpose
DELETE/admin/realms/{realm}/sessions/{sessionId}Terminate a user session.
GET/admin/realms/{realm}/organizationsList organizations.
GET/admin/realms/{realm}/organizations/countCount organizations.
GET/admin/realms/{realm}/organizations/{id}Get an organization.
POST/admin/realms/{realm}/organizationsCreate an organization.
PUT/admin/realms/{realm}/organizations/{id}Update an organization.
DELETE/admin/realms/{realm}/organizations/{id}Delete an organization.
GET/admin/realms/{realm}/ui-ext/infoUI-extension info.

When IGA is on for a non-master realm, the governed subset of these writes is captured into change requests rather than applied directly. See section 4.


2. Tide vendor, realm setup, settings, and branding (VendorResource)

Mounted by VendorResourceProvider (provider id vendorResources) at /admin/realms/{realm}/vendorResources/.... Every endpoint here requires manage-realm unless noted. Source: tidecloak-idp-extensions/tidecloak-key-provider/src/main/java/org/tidecloak/tidecustom/VendorResource.java.

POST setUpTideRealm

  • Path: POST /admin/realms/{realm}/vendorResources/setUpTideRealm (VendorResource.java:165)
  • Purpose: Provisions the Tide IdP and vendor-key component on the realm, the tide-claims scope and t.uho mapper, unmanaged attributes, and (unless skipped) free-tier licensing.
  • Auth: manage-realm.
  • Request (form): email (string, free-tier contact), isRagnarokEnabled (boolean, default true), skipLicense (boolean, default false; when true skips Stripe setup).
  • Response: 200 text/plain, JSON marker such as {"status":"idp-created"} or a free-tier licensing result.
  • Governed: No. Sets the IGA_VENDOR_PROVISIONING session flag so nested realm-config writes are exempt from IGA capture.

POST generate-initial-key

  • Path: POST /admin/realms/{realm}/vendorResources/generate-initial-key (VendorResource.java:298)
  • Purpose: Mints the realm's VVK, gVRK, gVRK certificate, and FirstAdmin authorizer via Midgard, completing key provisioning.
  • Auth: manage-realm.
  • Request: empty form body.
  • Response: 200 text/plain ("Key successfully generated"); on ORK signing/threshold failure throws a TideErrorException (code VENDOR_KEYGEN_FAILED, 500) after tearing down the vendor-key component.
  • Governed: No (sets IGA_VENDOR_PROVISIONING).

POST sign-idp-settings

  • Path: POST /admin/realms/{realm}/vendorResources/sign-idp-settings (VendorResource.java:475)
  • Purpose: Signs the realm's current Tide IdP settings (registration-allowed, backup, branding, per-client-origin auth) with the active VRK and stores the signatures and signed blob for ORK verification.
  • Auth: manage-realm.
  • Request: empty body.
  • Response: 200 text/plain (success); 400 if no Tide component/IdP; 500 on signing failure.
  • Governed: No (sets IGA_VENDOR_PROVISIONING). Also invoked internally on governance commit when registrationAllowed changes.

POST switch-vrk

  • Path: POST /admin/realms/{realm}/vendorResources/switch-vrk (VendorResource.java:110)
  • Purpose: Switches the active VRK to a specified generated VRK.
  • Auth: manage-realm.
  • Request: gvrk (query param, optional).
  • Response: 200 text/plain; 404 if the gVRK is not found; 500 on error.

POST readd-tide-key

  • Path: POST /admin/realms/{realm}/vendorResources/readd-tide-key (VendorResource.java:435)
  • Purpose: Re-adds the tide-vendor-key component.
  • Auth: As of source (VendorResource.java:435), this method does not call requireManageRealm(), unlike its sibling vendor endpoints. Described here as observed code behavior.
  • Response: 200 text/plain ("re-added tide-vendor-key"); 500 on error.

GET get-branding

  • Path: GET /admin/realms/{realm}/vendorResources/get-branding (VendorResource.java:530)
  • Purpose: Returns the realm's branding URLs.
  • Auth: manage-realm.
  • Response: 200 JSON { "backgroundUrl": "...", "logoUrl": "..." }; 400/500 on error.

POST set-branding

  • Path: POST /admin/realms/{realm}/vendorResources/set-branding (VendorResource.java:570)
  • Purpose: Sets the realm's branding URLs (null fields left unchanged).
  • Auth: manage-realm.
  • Request: JSON { "backgroundUrl"?: string, "logoUrl"?: string }.
  • Response: 200 text/plain; 400/500 on error.

POST tide-idp-admin-resources/images/upload

  • Path: POST /admin/realms/{realm}/tide-idp-admin-resources/images/upload (called from api-client vendor/index.ts:215)
  • Purpose: Uploads a branding image; returns a content hash and stored name.
  • Auth: manage-realm.
  • Request: multipart/form-data with file, fileName, fileType.
  • Response: { "hash": "...", "name": "..." }.

GET get-installations-provider

  • Path: GET /admin/realms/{realm}/vendorResources/get-installations-provider (VendorResource.java:983)
  • Purpose: Returns a client installation configuration (e.g. keycloak-oidc-keycloak-json) augmented with Tide fields.
  • Auth: view on the named client.
  • Request: clientId (query, client UUID), providerId (query, optional).
  • Response: 200, content type per provider; 500 on error.

GET get-tide-jwk

  • Path: GET /admin/realms/{realm}/vendorResources/get-tide-jwk (VendorResource.java:1021)
  • Purpose: Returns the EdDSA public key as a JWK.
  • Auth: manage-realm.
  • Response: 200 text/plain (JWK JSON); 400 if no component; 500 on error.

Scheduled-task endpoints

MethodPathPurposeSource
GET/admin/realms/{realm}/vendorResources/scheduledTasksList scheduled tasks (ScheduledTaskInfo[]).VendorResource.java:860
POST/admin/realms/{realm}/vendorResources/scheduledTasks/{taskName}/triggerTrigger a named task; 404 if the task is unknown.VendorResource.java:895
POST/admin/realms/{realm}/vendorResources/scheduledTasks/genVRK/scheduleSchedule the VRK generation task.VendorResource.java:932

All three require manage-realm. A read-only GET /realms/{realm}/vendorResources/scheduledTasks (non-admin) is also called by the SPA (vendor/index.ts:374).


3. Licensing (VendorResource Stripe / license endpoints)

Also on VendorResource; all require manage-realm. These surface the Stripe-backed licensing state and checkout flows.

MethodPathPurposeResponseSource
GET/admin/realms/{realm}/vendorResources/getLicenseDetailsLicense details for the realm.200 text/plain (license JSON) or 500.VendorResource.java:739
GET/admin/realms/{realm}/vendorResources/getSubscriptionStatusStripe subscription status (verbatim string).200 text/plain (status); throws TideErrorException VENDOR_SUBSCRIPTION_LOOKUP_FAILED (500) on lookup failure.VendorResource.java:776
GET/admin/realms/{realm}/vendorResources/isPendingLicenseActiveWhether a pending license is active.200 text/plain boolean string; 400/500.VendorResource.java:703
GET/admin/realms/{realm}/vendorResources/licenseHistoryLicense history.200 JSON array. As of source (VendorResource.java:1062) the method returns an empty array: it carries a TODO to rewire onto the IGA licensing-history pipeline (the old IGA's LicenseHistoryAdapter was removed during decoupling).VendorResource.java:1062
POST/admin/realms/{realm}/vendorResources/createStripeCheckoutSessionCreate a Stripe checkout session for a tier.303 text/plain redirect URL. Request (form): licensingTier.VendorResource.java:241
POST/admin/realms/{realm}/vendorResources/createCustomerPortalSessionCreate a Stripe customer-portal session.303 text/plain redirect URL. Request (form): redirectUrl.VendorResource.java:822
GET/admin/realms/{realm}/vendorResources/triggerLicenseRenewedEvent/{error}Emit a license-renewed admin event (test/diagnostic).200 text/plain. Path: error (boolean).VendorResource.java:963

For the procedure, see the License guide.


4. IGA governance / change requests

Mounted by IgaAdminResourceProviderFactory (provider id iga) with class @Path("iga") at /admin/realms/{realm}/iga/.... Source: tidecloak-iga-extensions/iga-core/src/main/java/org/tidecloak/iga/rest/IgaAdminResource.java. All endpoints require manage-realm unless noted.

These endpoints carry the governed status codes. For the conceptual model (capture, quorum, approver roles, scope mode) see Set up IGA and the Management API governance section. The in-repo tidecloak-iga-extensions/docs/qea-iga-api.md is the developer source for the lifecycle; this page reflects the endpoints the admin implementation actually uses, including ones that doc predates.

Change-request lifecycle

MethodPathPurposeKey responsesSource
GET/iga/change-requests?status={status}List CRs (default status=PENDING; also APPROVED, DENIED, CANCELLED).200 array of CR representations.IgaAdminResource.java:294
GET/iga/change-requests/{id}Fetch a single CR.200; 404 if unknown or in another realm.IgaAdminResource.java:391
POST/iga/change-requests/{id}/approveUnified admin-UI lane: records the caller's approval and auto-commits when quorum is reached. For multiAdmin it runs two-phase: phase 1 (no body) returns a requestModel to sign in the enclave; phase 2 ({"requestModel": "..."}) submits the signed carrier.200 (shape varies by mode: recorded with committed/authCount/threshold, or needs-approval with requestModel); governed codes below; 409 NOT_MULTI_ADMIN / NOT_TIDE_ATTESTOR; 400 APPROVAL_MODEL_INVALID.IgaAdminResource.java:1093
POST/iga/change-requests/{id}/commitApply-only: commits a CR that has already reached quorum (replay and apply). Does not record a new approval.200 {committed,changeRequestId,status,changeRequest}; governed codes below.IgaAdminResource.java:623
POST/iga/change-requests/{id}/authorizeLegacy single-phase authorize (records one approval, auto-commits at quorum). Refuses multiAdmin realms. Retained for internal/bulk reuse.200; 403 FORBIDDEN_APPROVER_ROLE; 409 (not PENDING / already signed / MULTIADMIN_REQUIRES_APPROVAL_ENCLAVE).IgaAdminResource.java:529
POST/iga/change-requests/{id}/denyDeny a CR.204 No Content; 404.IgaAdminResource.java:1781
POST/iga/change-requests/bulk-authorizeDrain many CRs in one call (typically the toggle-on ADOPT set).200 {results[], summary} (read per-CR status); 400 on bad input; 429 if a bulk run already holds the per-realm lock.IgaAdminResource.java:1334
PUT/iga/change-requests/{id}Replace the CR's rows; deletes all authorizations (re-signing required).200; 400 if rows missing; 404. Body {"rows":[...]}.IgaAdminResource.java:1749
POST/iga/adoptCreate a manual ADOPT change request for an entity.201 {changeRequestId,entityType,entityId}; 400; 409 ALREADY_ATTESTED. Body {entityType,entityId}.IgaAdminResource.java:1807

Two-phase approval (multiAdmin, legacy split)

Preserved for back-compat; the unified /approve endpoint above is what current admin UIs call.

MethodPathPurposeSource
GET/iga/change-requests/{id}/approval-modelPhase 1: build the enclave requestModel to sign. Returns 409 NOT_MULTI_ADMIN/NOT_TIDE_ATTESTOR off-mode.IgaAdminResource.java:913
POST/iga/change-requests/{id}/approval-modelPhase 2: submit the signed requestModel; records approval and returns quorum status (does not auto-commit).IgaAdminResource.java:972

Diagnostics, preview, and comments

MethodPathPurposeSource
GET/iga/change-requests/{id}/diagnostic-bundleRead-only diagnostic snapshot of a CR (diag_kind: iga_cr_bundle, rows, authorizations, threshold, approver role).IgaAdminResource.java:431
POST/iga/change-requests/{id}/first-admin-sign-previewDenormalized signing-payload preview (no cryptography).IgaAdminResource.java:1732
GET/iga/change-requests/{id}/commentsList comments.IgaAdminResource.java:1859
POST/iga/change-requests/{id}/commentsAdd a comment ({comment} or {body}, max 2000 chars; 201).IgaAdminResource.java:1878
PUT/iga/change-requests/{id}/comments/{commentId}Edit a comment (author only; 403 otherwise).IgaAdminResource.java:1920
DELETE/iga/change-requests/{id}/comments/{commentId}Delete a comment (author or manage-realm; 204).IgaAdminResource.java:1965

Governed status codes

StatusMeaning / error code
200 OKList / get, or an approve / commit that succeeded.
201 CreatedADOPT created.
202 AcceptedA governed admin write was captured into a CR (returned by the captured write itself, not by these lifecycle endpoints). Location points at the CR.
204 No ContentDeny, comment delete, or a policy delete.
400 Bad RequestAPPROVAL_MODEL_INVALID; missing rows; bad bulk input; oversized comment.
403 ForbiddenFORBIDDEN_APPROVER_ROLE (caller lacks the required approver role); non-author comment edit; reserved policy name.
404 Not FoundUnknown CR id; ENTITY_VANISHED on a commit whose ADOPT target was deleted out of band.
409 ConflictCR not PENDING; same admin already signed; MULTIADMIN_REQUIRES_APPROVAL_ENCLAVE (legacy authorize lane refusing a multiAdmin CR); NOT_MULTI_ADMIN / NOT_TIDE_ATTESTOR (two-phase endpoints off-mode); ALREADY_ATTESTED (adopt); MAPPER_CLAIM_CONFLICT (replay would duplicate a protocol-mapper claim).
412 Precondition FailedCommit gate not met: QUORUM_NOT_MET (multiAdmin commit below quorum), DEPENDENCY_NOT_MET (prerequisite CR not approved), PENDING_ADMIN_GRANTS (REGEN_ADMIN_POLICY committing while covered admin grants are still pending).
429 Too Many RequestsA bulk-authorize is already running for this realm.

Realm / role policies

Threshold-and-approver policy records. Reads are available to any authenticated admin; writes require manage-realm. The reserved name tide-realm-admin is read-only (writes return 403).

MethodPathPurposeSource
GET/iga/role-policiesList named policies.IgaAdminResource.java:2110
GET/iga/role-policies/{id}Get a policy by id.IgaAdminResource.java:2120
GET/iga/role-policies/name/{name}Get a policy by name.IgaAdminResource.java:2132
POST/iga/role-policiesUpsert a policy.IgaAdminResource.java:2145
DELETE/iga/role-policies/name/{name}Delete a policy by name (403 for the reserved name).IgaAdminResource.java:2200
DELETE/iga/role-policies/{id}Delete a policy by id.IgaAdminResource.java:2222

Authorizers

IGA authorizer records (providerId, type, authorizer, authorizerCertificate). All require manage-realm.

MethodPathPurposeKey responsesSource
GET/iga/authorizers?type={type}List authorizers, optionally filtered by type.200 array.IgaAdminResource.java:2008
GET/iga/authorizers/{id}Get an authorizer by id.200; 404 if unknown or in another realm.IgaAdminResource.java:2026
POST/iga/authorizersCreate an authorizer. Body requires providerId, type, authorizer, authorizerCertificate.201; 400 if the body or any required field is missing.IgaAdminResource.java:2039
DELETE/iga/authorizers/{id}Delete an authorizer.204; 404 if unknown or in another realm.IgaAdminResource.java:2083

Forseti contracts

Reusable smart-contract code chunks (keyed by body hash). All require manage-realm.

MethodPathPurposeKey responsesSource
GET/iga/forseti-contractsList contracts for the realm.200 array.IgaAdminResource.java:2248
GET/iga/forseti-contracts/{id}Get a contract by id.200; 404 if unknown or in another realm.IgaAdminResource.java:2259
POST/iga/forseti-contractsUpsert a contract (idempotent on body hash). Body requires contractCode (max 1048576 chars), optional name.200; 400 if contractCode missing or oversized.IgaAdminResource.java:2272
DELETE/iga/forseti-contracts/{id}Delete a contract by id.204; 404 if unknown or in another realm.IgaAdminResource.java:2302

Server certificates

Workload TLS / SPIFFE server-cert request drafts. All require manage-realm.

MethodPathPurposeKey responsesSource
GET/iga/server-certsList all server-cert drafts.200 array.IgaAdminResource.java:2320
GET/iga/server-certs/activeList active server-cert drafts.200 array.IgaAdminResource.java:2330
GET/iga/server-certs/{id}Get a draft by id.200; 404 if unknown or in another realm.IgaAdminResource.java:2340
GET/iga/server-certs/instance/{instanceId}List drafts for a workload instance.200 array.IgaAdminResource.java:2352
POST/iga/server-certs/requestFile a cert request. Body requires clientId, instanceId, publicKey (max 4096 chars); optional spiffeId (max 512), publicKeyFingerprint, requestedLifetime, signedPolicy (max 8192).201; 400 on missing/oversized field.IgaAdminResource.java:2364
POST/iga/server-certs/{id}/issueMark a draft issued. Body requires certificate, trustBundle.200; 400 if either missing; 404.IgaAdminResource.java:2422
POST/iga/server-certs/{id}/revokeRevoke an issued cert.200; 404.IgaAdminResource.java:2452
DELETE/iga/server-certs/{id}Delete a draft.204; 404.IgaAdminResource.java:2467

Licensing drafts and history

Realm license install/rotate draft flow plus the append-only license-history audit log. All require manage-realm.

MethodPathPurposeKey responsesSource
POST/iga/licensing/triggerCreate a licensing draft. Body requires actionType (INSTALL_LICENSE or ROTATE_LICENSE).201; 400 if actionType missing or not one of the two values.IgaAdminResource.java:2485
GET/iga/licensing/draftsList licensing drafts.200 array.IgaAdminResource.java:2513
GET/iga/licensing/drafts/{id}Get a draft by id.200; 404.IgaAdminResource.java:2523
DELETE/iga/licensing/drafts/{id}Delete a draft.204; 404.IgaAdminResource.java:2535
POST/iga/licensing/drafts/{draftId}/issueIssue a license against a draft. Body requires providerId, vrk, gvrk, signature; optional gvrkCertificate.200; 400 on missing field; 404.IgaAdminResource.java:2594
GET/iga/licensing/historyList license-history records.200 array.IgaAdminResource.java:2553
GET/iga/licensing/history/{id}Get a history record by id.200; 404.IgaAdminResource.java:2563
GET/iga/licensing/history/excluding-active?activeGvrk={gvrk}List history records excluding the one for activeGvrk.200 array.IgaAdminResource.java:2575

5. tide-admin (admin-UI governance bridge)

The SPA api-client (tidecloak-key-provider/frontend/packages/api-client/src/tide-admin/index.ts) drives a tide-admin API surface that wraps the IGA change-request lifecycle for the admin UI. Two distinct realities sit behind this client, and the entries below separate them:

  • Server-resolved. The provider id tide-admin is served by TideAdminCompatResource (mounted by TideAdminCompatResourceProviderFactory, @Path("tide-admin")) at /admin/realms/{realm}/tide-admin/.... Source: tidecloak-iga-extensions/iga-core/src/main/java/org/tidecloak/iga/rest/TideAdminCompatResource.java. In the current source tree that class serves exactly three endpoints (toggle-iga, iga-status, toggle-iga/status/{jobId}).
  • Routed to iga. Several api-client methods named in the tide-admin module call the IGA resource directly under /admin/realms/{realm}/iga/... (see section 4); the realm-policy reads/writes are the clearest case.
  • Legacy compat, not in this build. The remaining tide-admin/* paths the api-client references (change-set/*, realm-policy/*, server-cert/*, users/{id}/draft/status, and the per-mapping draft-status probes) have no @Path in the current Java sources. The api-client treats a 404 from these as a no-op (empty list / {} / zero counts) so a build without the legacy surface degrades quietly. They are documented here by their api-client call site as observed behavior; their server resource class is not present in source.

Server-resolved tide-admin endpoints

Mounted on TideAdminCompatResource. All require manage-realm unless noted.

MethodPathPurposeKey responsesSource
POST/tide-admin/toggle-igaFlip IGA on/off for the realm (next = !current). On OFF to ON (non-master) it provisions the tide-realm-admin approver role, sets iga.attestor=tide and EdDSA (when the VRK is active), runs the ADOPT scan, invalidates sessions, and runs the firstAdmin auto-commit sweep. On ON to OFF (non-master) it captures a governed DISABLE_IGA change request instead of flipping directly. Body (form): isIGAEnabled (informational), optional jobId for progress polling.200 {enabled, scan?, autoCommit?, approverRoleRepoint?, warning?}; 202 (ON to OFF, governed DISABLE_IGA CR filed); 409 SIDECAR_CAP_EXCEEDED.TideAdminCompatResource.java:104
GET/tide-admin/iga-statusReport whether IGA is enabled for the realm.200 {enabled}. Auth: view-realm.TideAdminCompatResource.java:570
GET/tide-admin/toggle-iga/status/{jobId}Poll live progress for a toggle-on job: {jobId, state, currentStageId, stages[], error}.200; 404 UNKNOWN_JOB.TideAdminCompatResource.java:587

tide-admin methods routed to the iga resource

These api-client methods sit in the tide-admin module but call /admin/realms/{realm}/iga/.... See Realm / role policies in section 4 for the server entries.

api-client methodPath calledPurposeSource (api-client)
getChangeSetCountsGET /iga/change-requests?status=PENDINGDerive {users, roles, clients, groups, total} by bucketing the PENDING CR list on entityType. 404/403 collapse to all-zeros.tide-admin/index.ts:65
listRealmPolicies / listSshPoliciesGET /iga/role-policiesList named realm policies. 404/403 collapse to [].tide-admin/index.ts:352, :454
getRealmPolicyByNameGET /iga/role-policies/name/{name}Find a policy by name. 404 resolves to null.tide-admin/index.ts:366
getRealmPolicyByIdGET /iga/role-policies/{id}Find a policy by id. 404 resolves to null.tide-admin/index.ts:385
upsertRealmPolicyPOST /iga/role-policiesUpsert a named policy. Reserved name tide-realm-admin returns 403.tide-admin/index.ts:404
deleteRealmPolicyByNameDELETE /iga/role-policies/name/{name}Delete a policy by name.tide-admin/index.ts:425
deleteRealmNamedPolicyByIdDELETE /iga/role-policies/{id}Delete a policy by id.tide-admin/index.ts:439

Legacy compat tide-admin paths (not in current source)

The following are the paths the api-client targets under /admin/realms/{realm}/tide-admin/.... No @Path for them exists in the current Java sources, so on the current build they return 404 and the api-client degrades to a no-op (empty/{}/zero). Documented from the api-client call site; consult tide-admin/index.ts for the request/response Zod schemas.

MethodPathPurpose (per api-client)Source (api-client)
GET/tide-admin/change-set/all/requestsList all change-set bundles (governance inbox).tide-admin/index.ts:121, :130
GET/tide-admin/change-set/{id}/activityTimeline (requestor + approval/comment events) for one bundle. 404 to empty timeline.tide-admin/index.ts:148
POST/tide-admin/change-set/sign/batchOperator approval entry point for a batch; Tide realms return requiresApprovalPopup + draft requests.tide-admin/index.ts:169
POST/tide-admin/change-set/commit/batchFinalize an approved batch.tide-admin/index.ts:194
POST/tide-admin/change-set/cancel/batchDrop a draft/pending batch.tide-admin/index.ts:212
GET/tide-admin/change-set/{type}/requestsLegacy per-bucket (clients/users/roles/groups) pending-CR list. 404 to [].tide-admin/index.ts:690
POST/tide-admin/change-set/signLegacy single-request sign ({changeSetId, changeSetType, actionType}).tide-admin/index.ts:717
POST/tide-admin/change-set/commitLegacy single-request commit (same body).tide-admin/index.ts:736
POST/tide-admin/change-set/{id}/commentsAdd a comment to a bundle.tide-admin/index.ts:566
PUT/tide-admin/change-set/{id}/comments/{commentId}Edit a comment (author-gated).tide-admin/index.ts:594
DELETE/tide-admin/change-set/{id}/comments/{commentId}Delete a comment (author-gated).tide-admin/index.ts:622
GET/tide-admin/users/{id}/draft/statusUser-level draft state {draftStatus, deleteStatus}. 404 to {}.tide-admin/index.ts:246
GET/tide-admin/users/{userId}/roles/{roleId}/draft/statusPer-role draft state for a user role-mapping. 404 to {}.tide-admin/index.ts:268
GET/tide-admin/composite/{parentId}/child/{childId}/draft/statusDraft state for a composite-role mapping. 404 to {}.tide-admin/index.ts:290
GET/tide-admin/forseti-contractsList Forseti contracts (compat surface).tide-admin/index.ts:312
PUT/tide-admin/forseti-contractsUpsert a Forseti contract (idempotent on body hash).tide-admin/index.ts:326
GET/tide-admin/realm-policyCurrent realm-policy state (status always present). 404 to {status:"none"}.tide-admin/index.ts:472
POST/tide-admin/realm-policy/pendingPropose a new realm policy (template or raw contract code).tide-admin/index.ts:489
POST/tide-admin/realm-policy/commitFinalize an approved realm policy (409 below quorum).tide-admin/index.ts:508
POST/tide-admin/realm-policy/request-deletePropose deletion of an active realm policy.tide-admin/index.ts:523
POST/tide-admin/realm-policy/commit-deleteFinalize an approved delete proposal.tide-admin/index.ts:538
DELETE/tide-admin/realm-policyDirect delete of a not-yet-committed (pending) policy.tide-admin/index.ts:554
GET/tide-admin/server-cert/requestsList SPIFFE server-cert requests (PENDING/ACTIVE/DENIED). 404 to [].tide-admin/index.ts:647
POST/tide-admin/server-cert/revokeRevoke an issued server cert ({instanceId}).tide-admin/index.ts:665

A separate tideAdminResources resource (provider distinct from tide-admin) serves one method the api-client calls under /admin/realms/{realm}/tideAdminResources/...:

MethodPathPurpose (per api-client)Source (api-client)
POST/tideAdminResources/get-required-action-linkTide-aware analogue of users/{id}/execute-actions-email: returns the required-action link as text/plain instead of mailing it. Bookkeeping (userId, lifespan, redirect_uri, client_id) on the query string; body is a bare JSON array of required-action names.tide-admin/index.ts:763

6. Ragnarok backup and offboarding

Mounted by the Ragnarok admin resource provider (provider id ragnarok) at /admin/realms/{realm}/ragnarok/.... Source: ragnarok/ragnarok-tidecloak-spi/src/main/java/org/ragnarok/RagnarokAdminResources/RagnarokAdminRealmResource.java. All require manage-realm. For the procedure, see the Ragnarok guide.

POST toggle-ragnarok

  • Path: POST /admin/realms/{realm}/ragnarok/toggle-ragnarok (RagnarokAdminRealmResource.java:193)
  • Purpose: Enables offboarding backup: runs the local EnableOffboard VRK ceremony, stores the encrypted-VVK backup shard (eVVK) on the vendor-key component, enforces email-as-login prerequisites, and sets backupOn on the Tide IdP.
  • Auth: manage-realm.
  • Request (form): isRagnarokEnabled (boolean; must be true. Once enabled, backup cannot be disabled).
  • Response: 200 text/plain ("Offboarding backup has been enabled."); 400 if isRagnarokEnabled=false or the vendor-key component is absent.
  • Governed: No (ungoverned, local VRK sign, no quorum).

POST trigger-offboarding

  • Path: POST /admin/realms/{realm}/ragnarok/trigger-offboarding (RagnarokAdminRealmResource.java:104)
  • Purpose: Files an OFFBOARD_REALM change request (entity type REALM) that, on commit, runs the destructive teardown (reconstruct VVK from eVVK, make the realm self-custodial, remove the Tide IdP, restore password login).
  • Auth: manage-realm.
  • Request: empty body.
  • Response:
    • 202 Accepted with Location and X-Change-Request-Id headers when the CR is filed.
    • 412 Precondition Failed text/plain when a pre-flight gate fails: backup not enabled (eVVK missing) or fewer active tide-realm-admins than the offboard threshold.
    • 409 Conflict if a pending REALM-scoped CR already exists.
  • Governed: Yes. Commit floor is max(normal quorum, iga.offboardMinAdmins) (default offboardMinAdmins = 3).

GET change-set/offboarding/requests

  • Path: GET /admin/realms/{realm}/ragnarok/change-set/offboarding/requests (RagnarokAdminRealmResource.java:91)
  • Purpose: Legacy listing of offboarding requests.
  • Auth: manage-realm.
  • Response: 200 empty JSON array (no longer backed by a store; offboarding CRs surface through the standard IGA change-request listing). The SPA discovers a pending offboard by filtering GET /iga/change-requests?status=PENDING for an OFFBOARD_REALM CR (ragnarok/index.ts:158).

7. Public and console config

Pre-authentication resources under /realms/{realm}/.... No admin token. Source: tidecloak-idp-extensions/tidecloak-key-provider/src/main/java/org/tidecloak/... (PublicResource, TideConsoleResource).

GET public/get-tide-config

  • Path: GET /realms/{realm}/public/get-tide-config (PublicResource.java:28)
  • Purpose: Returns public, pre-auth Tide adapter configuration for a client: vendorId, homeOrkUrl, per-origin client-origin-auth-<origin> signatures, and branding URLs.
  • Auth: public.
  • Request: clientId (query).
  • Response: 200 JSON; 404 if the client is unknown; 500 on error.

GET tide-console/tidecloak.json

  • Path: GET /realms/{realm}/tide-console/tidecloak.json (TideConsoleResource.java:83)
  • Purpose: Origin-bound adapter install config the SPA fetches before login: realm, auth-server-url, resource (tide-admin-console), public-client, client-origin-auth-<origin> entries, gVVK, vvkId, orkUrl, payerPublic, threshold T/N, branding.
  • Auth: public.
  • Response: 200 JSON when the realm is Tide-enabled and the console origin is signed; 404 ({}) otherwise. No-cache.

GET tide-console/bootstrap.json

  • Path: GET /realms/{realm}/tide-console/bootstrap.json (TideConsoleResource.java:93)
  • Purpose: Pre-auth bootstrap descriptor so the SPA can discover how to start OIDC login on an un-provisioned realm: realm, auth-server-url, bootstrapRealm (master), bootstrapClientId (tide-console-bootstrap). Self-heals the bootstrap client if missing.
  • Auth: public.
  • Response: 200 JSON (always available, even on un-provisioned realms). No-cache.

Console SPA serving

MethodPathPurposeSource
GET/realms/{realm}/tide-console/ and /index.htmlServe the SPA shell (index.html) with window.__TIDE_BASE__ injected and /__TIDE_BASE__/ rewritten to the realm console base. No-cache.TideConsoleResource.java:68, :73
GET/realms/{realm}/tide-console/assets/{path}Serve hashed assets (immutable, 1-year cache). 400 if path contains ..; 404 if absent.TideConsoleResource.java:103
GET/realms/{realm}/tide-console/{path}Catch-all: serve embedded side files (e.g. silent-check-sso.html) or fall back to the SPA shell for client-side routes.TideConsoleResource.java:115